/*
 * Created on 2008-3-7
 *
 * TODO 
 */
package jacky.lanlan.song.extension.struts.interceptor;

import java.lang.reflect.Method;
import java.util.Map;

import jacky.lanlan.song.extension.struts.InfrastructureKeys;
import jacky.lanlan.song.extension.struts.action.ValueStack;
import jacky.lanlan.song.extension.struts.util.ConcurrentCache;
import jacky.lanlan.song.extension.struts.util.ReflectionUtils;
import jacky.lanlan.song.extension.struts.util.ReturnableHandler;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.struts.Globals;

/**
 * 处理Cancell操作的拦截器，优先级100。
 * @author Jacky.Song
 */
public class CancellInterceptor extends ActionInterceptorAdapter {

	//Cancell方法缓存 [全类名+方法名 -> 方法]
	private final ConcurrentCache<String,Method,Object[]> cancelledMethodCache=
		new ConcurrentCache<String,Method,Object[]>(
				new ReturnableHandler<Object[],Method>(){ //参数 [0]为actionClass，[1]为Cancell方法名
    			public Method doWith(Object[] data) {
    				Class<?> actionClass=(Class<?>) data[0];
    				String methodName=(String) data[1];
    				Method cancelled = ReflectionUtils.findMethod(
    						actionClass, methodName, InfrastructureKeys.METHOD_PARAM);// 寻找Cancell方法
    				
    				if(cancelled==null) {
    					throw new UnsupportedOperationException(
    							"没有与方法 ["+methodName.split("_")[0]+"] 匹配的Cancell方法 ["+methodName+"]");
    				}
    				return cancelled;
    			}
				}
		);
	
	@SuppressWarnings({ "unused", "unchecked" })
	public String preHandle(HttpServletRequest request,
			HttpServletResponse response,Object action) throws Exception {
		//针对Cancell操作
		if(request.getAttribute(Globals.CANCEL_KEY) != null) {
			//寻找执行方法对应的cancell方法
			Method execMethod=(Method) request.getAttribute(InfrastructureKeys.EXECUTION);
			String cancellMethodName=execMethod.getName()+"_Cancelled";
			Class<?> actionClass=action.getClass();
			Method cancelled=cancelledMethodCache.cacheIfAbsent(
					actionClass.getName()+cancellMethodName, new Object[] {actionClass,cancellMethodName});
			
			ValueStack vs=(ValueStack)request.getAttribute(InfrastructureKeys.VSAC);
			Map<String,String> reqData = (Map)request.getAttribute(InfrastructureKeys.REQ_DATA);
			return (String) cancelled.invoke(action, new Object[] {vs,reqData});//调用Cancell操作的方法
		}
		return null; //继续调用下面的拦截器
	}

	public int priority() {
		return 100;//优先级在默认拦截器中最高
	}
}
